#include "find_similar_texture.h"
#include "messiah/resource/repo/repo_item.h"
#include "messiah/resource/repo/repo_res_texture.h"
#include "fileio/fileio.h"
#include "debug/logger.h"
#include "external/blockhash/blockhash.h"

#include <sstream>

namespace renderit
{
	namespace messiah
	{
		static const char * get_phash(const repo_item * item)
		{
			repo_res_texture * ti = (repo_res_texture*)(item->repo_res_);
			image::image * img = ti->get_image();
			if (img)
			{
				return bits_to_hexhash((int*)(img->get_blockhash()), image::BLOCK_HASH_BITS);
			}
			return "";
		}

		static void copy_texture(const std::string& dir, repo_item * item)
		{
			std::string fpath = fileio::join(item->repo_res_dir_, "source.tga");
			std::string dest = fileio::join(dir, item->guid_);
			dest += ".tga";
			fileio::copy_file(fpath, dest);
		}

		void find_similar_texture(repository * repo)
		{
			std::vector<std::pair<repo_item*, repo_item*>> similar_pairs;
			const std::vector<repo_item*>& textures = repo->get_items_by_type(EResourceType_Texture);
			bool b = true;
			for (uint32 i = 0; i < textures.size(); ++i)
			{
				repo_res_texture * ti = (repo_res_texture*)(textures[i]->repo_res_);
				image::image * ii = ti->get_image();
				if (!ii)
				{
				//	logger::warn("Texture:%s Missing!", textures[i]->guid_.c_str());
					continue;
				}
				for (uint32 j = i + 1; j < textures.size(); ++j)
				{
					repo_res_texture * tj = (repo_res_texture*)(textures[j]->repo_res_);
					image::image * ij = tj->get_image();
					if (!ij)
					{
					//	logger::warn("Texture:%s Missing!", textures[j]->guid_.c_str());
						continue;
					}

					if (image::hamming_distance(ii, ij) < 5)
					{
						similar_pairs.push_back({ textures[i], textures[j] });
						if (similar_pairs.size() >= 100000)
						{
							b = false;
							break;
						}
					}
				}
				if (!b)
				{
					break;
				}
			}

			logger::info("Similar Pair Count:%d", similar_pairs.size());
			logger::info("Processing:0/%d", similar_pairs.size());

			fileio::remove_file("./similar_texture/");
			fileio::ensure_dir("./similar_texture/");

			uint32 index = 0;

			std::stringstream ss;
			for (auto& p : similar_pairs)
			{
				index++;
				if (index % 10 == 0)
				{
					logger::back_line();
					logger::info("Processing:%d/%d", index, similar_pairs.size());
				}

				std::string dir = fileio::join("./similar_texture/", p.first->guid_);
				fileio::ensure_dir(dir);
				copy_texture(dir, p.first);
				copy_texture(dir, p.second);
				ss << p.first->guid_ << " " << std::hex << get_phash(p.first) << " " << p.first->package_ << "/" << p.first->name_ << std::endl;
				ss << p.second->guid_ << " " << std::hex << get_phash(p.second) << " " << p.second->package_ << "/" << p.second->name_ << std::endl;
				ss << std::endl;
			}

			fileio::ifile * f = fileio::open("./similar_texture/textures.txt", fileio::EOpen_CreateAlways | fileio::EOpen_Write);
			if (f)
			{
				std::string s = ss.str();
				f->write(s.data(), s.size());
				f->close();
			}

			logger::info("Find Similar Textures Success!");
		}
	}
}